package gov.dhs.cis.soa.readers.rsa;

import gov.dhs.cis.soa.Utils;
import gov.dhs.cis.soa.data.Actor;
import gov.dhs.cis.soa.data.Description;
import gov.dhs.cis.soa.data.Processes;
import gov.dhs.cis.soa.data.Service;

import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

import javax.xml.namespace.NamespaceContext;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;

import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.util.CellRangeAddress;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class ReportRSACompModel {
	String PROC_XPATH = "//packagedElement[@xmi:type='uml:Class']";

	String XMI_NS = "http://schema.omg.org/spec/XMI/2.1";
	final String DELIM = ", ";
	public static final String OUT_FILE = "ComponentModel.xls";
	FileOutputStream fstream = null;
    BufferedWriter out = null;
    HSSFWorkbook book = null;
    HSSFSheet sheet = null;
	String[] header = new String[] { "Application Name", "Stereo Type", "Component", "Description"};  
    int nCurrentRow = 0;

	XPathFactory xpathFactory = XPathFactory.newInstance();
	XPathExpression stereoTypeExpr = null;

	private NamespaceContext getNameSpaceCtx () {
		NamespaceContext ctx = new NamespaceContext() {
	        public String getNamespaceURI(String prefix) {
	        	//System.out.println("Name space requested : " + prefix);
	            String uri = null;
	            if (prefix.equals("xmi")) {
	                uri = XMI_NS;
	            }
	            return uri;
	        }
	       
	        // Dummy implementation - not used!
	        public Iterator getPrefixes(String val) { return null; }
	       
	        // Dummy implemenation - not used!
	        public String getPrefix(String uri) { return null; }
	    };
	    return ctx;
	}
	
	private XPathExpression getXPathExpression(String xpathStr) throws Exception {
		XPath xpath = xpathFactory.newXPath();
		xpath.setNamespaceContext(getNameSpaceCtx());
		// XPath Query for showing all nodes value
		XPathExpression expr = xpath.compile(xpathStr);
		return expr;
	}

	private NodeList evaluate(Object evalOn, XPathExpression expr) throws Exception {
		Object result = expr.evaluate(evalOn, XPathConstants.NODESET);
		NodeList nodes = (NodeList) result;
		return nodes;
	}
	
	public void transform(String inXML) throws Exception {
		long startTime = System.currentTimeMillis();
		Document doc = getXMLDocument(inXML);
		//prep req values
		stereoTypeExpr = getXPathExpression("eAnnotations/details/@key");

		fstream = new FileOutputStream(OUT_FILE);

	    book = new HSSFWorkbook();
	    sheet = book.createSheet("Report");
		printHeader();
		ArrayList<Processes> servList = extractComponents(doc);
		
		//write all the processes..
		for(Processes procObj : servList) {
			HSSFRow row = sheet.createRow(nCurrentRow++);
			int i = 0;
			
			//System.out.println("<<" + procObj.stereotype + ">> " + procObj.name + ": <<" + stereoType + ">> " + relationName + " = " + supplierName);
			HSSFCell cell = row.createCell(i++);
			cell.setCellValue(procObj.IST);
			cell = row.createCell(i++);
			cell.setCellValue(procObj.stereotype);
			cell = row.createCell(i++);
			cell.setCellValue(procObj.name);
			cell = row.createCell(i++);
			cell.setCellValue(procObj.descText);
			cell = row.createCell(i++);
		}
		if(out != null) {
			out.close();
		}
		if(book != null) {
			CellRangeAddress range = new CellRangeAddress(0, this.nCurrentRow-1, 0, header.length-1);
			sheet.setAutoFilter(range);
			book.write(fstream);
			fstream.close();
		}

		//printXML();
		
		System.out.println("Time took : " + (System.currentTimeMillis() - startTime)/1000);
	}
	
	private ArrayList<Processes> extractComponents(Document doc) throws Exception {
		ArrayList<Processes> servList = new ArrayList<Processes>();
		
		NodeList nodes = evaluate(doc, getXPathExpression(PROC_XPATH));
		
		Node procNode = null;

		XPathExpression descExpr = getXPathExpression("ownedComment/body/text()");
		
		for (int i = 0; i < nodes.getLength(); i++) {
			Processes process = new Processes();
			
			procNode = nodes.item(i);
			process.name = procNode.getAttributes().getNamedItem("name").getNodeValue();

			process.stereotype = getStereoType(procNode);
			
			//parent application Name
			process.IST = procNode.getParentNode().getAttributes().getNamedItem("name").getNodeValue();
			
			//not needed now, but works
			NodeList procAttrbNodes = evaluate(procNode, descExpr);
			process.descText = procAttrbNodes.item(0).getNodeValue();
			
			servList.add(process);
		}
		return servList;
	}
	
	private String getStereoType(Node node) throws Exception {
		//XPathExpression stereoTypeExpr = getXPathExpression("eAnnotations/details/@key");
		NodeList attrbNodes = evaluate(node, stereoTypeExpr);
		if(attrbNodes == null || attrbNodes.getLength() == 0)
			return "NONE";
		String stereotype = attrbNodes.item(0).getNodeValue();
		return stereotype;
	}

	
	
	private Document getXMLDocument(String inXML)
			throws ParserConfigurationException, SAXException, IOException {
		InputStream inXMLStream = this.getClass().getClassLoader().getResourceAsStream(inXML);

		DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
		domFactory.setNamespaceAware(true);
		DocumentBuilder builder = domFactory.newDocumentBuilder();
		Document doc = builder.parse(inXMLStream);
		return doc;
	}
	
	private void printHeader() {
		HSSFRow row = sheet.createRow(nCurrentRow++);
		String data = "";
		for(int i = 0; i < header.length; i++) {
			data = (String)header[i];
			HSSFCell cell = row.createCell(i);
			HSSFCellStyle style = book.createCellStyle();
			style.setFillForegroundColor(IndexedColors.LIGHT_ORANGE.getIndex());
			style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
			style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
			style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
			cell.setCellStyle(style);
			cell.setCellValue(data);
		}
	}
}
